Introduction

This script is used to analyze siRNA screen validation data obtained with High-Content Image analysis. In particular, the siRNA library used is the Dharmacon generated by Andria Schibler and Pedja Jevtic, based on the primary siRNA screen results using the Epigenetics and Custom Nuclear Envelope libraries from ThermoFisher.

The siRNA library was originally received dried in 96 well plates at 0.25 nM. It was resuspended and mixed in 50 ul nuclease-free water to obtain a final concentration of 5 uM, frozen overnight and then thawed to increase oligo siRNA solubility.45 ul were aspirated from the original source plate and dispensed into separate wells to generate a 384 well master Plate. These siRNAs occupied columns 1 to 22 (Partial). All these liquid handling operations were performed using a PerkinElmer Janus instrument, which output all the liquid handling operations logs as text files.384 well imaging ready plates containing spotted siRNA (300 nl) were generated using an Echo525. 300 of ul control siRNA (5uM) were then added to their respective wells in columns 22, 23 and 24. The imaging assay ready plates were sealed with aluminum sealing foil and stored at -20oC until use.

Imaging Assay plates were dried, frozen and then used in reverse transfection experiments. For reverese transfection, plates were thawed, spinned and 20 ul of Optimem + 0.05 ul/well of RNAiMax were added to the plates and incubated for 30’. Then 20 ul of cells were added on top of the siRNA/RNAiMax mix and incubated for 72 hrs.

Fixed and stained plates were imaged on an Opera QEHS microscope using a 40X water immersion objectives. Images were analyzed in Columbus 2.8.1, and image analysis results were exported as tab delimited .txt files.

The script reads library reformatting files used on the Echo (Containing the siRNA layout), the Columbus image analysis results and generates statistical analysis.

Ab markers:

Load packages.

library(plyr)
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.1     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.1     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     ── Conflicts ────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::arrange()   masks plyr::arrange()
✖ purrr::compact()   masks plyr::compact()
✖ dplyr::count()     masks plyr::count()
✖ dplyr::desc()      masks plyr::desc()
✖ dplyr::failwith()  masks plyr::failwith()
✖ dplyr::filter()    masks stats::filter()
✖ dplyr::id()        masks plyr::id()
✖ dplyr::lag()       masks stats::lag()
✖ dplyr::mutate()    masks plyr::mutate()
✖ dplyr::rename()    masks plyr::rename()
✖ dplyr::summarise() masks plyr::summarise()
✖ dplyr::summarize() masks plyr::summarize()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(knitr)
library(data.table)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.14.8 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com
**********
This installation of data.table has not detected OpenMP support. It should still work but in single-threaded mode.
This is a Mac. Please read https://mac.r-project.org/openmp/. Please engage with Apple and ask them for support. Check r-datatable.com for updates, and our Mac instructions here: https://github.com/Rdatatable/data.table/wiki/Installation. After several years of many reports of installation problems on Mac, it's time to gingerly point out that there have been no similar problems on Windows or Linux.
**********

Attaching package: ‘data.table’

The following objects are masked from ‘package:lubridate’:

    hour, isoweek, mday, minute, month, quarter, second, wday, week, yday,
    year

The following objects are masked from ‘package:dplyr’:

    between, first, last

The following object is masked from ‘package:purrr’:

    transpose
library(ggthemes)
library(viridis)
Loading required package: viridisLite

Read the siRNA layouts and generate a control layout

Set channel variable names.

green_name = "LMNB"
red_name = "LMNA"

Read the siRNA layout information provided by Dharmacon and select only relevant columns. The custom cherry pick work list file that was generated by the Janus to reformat the siRNA oligos from 96 well to 384.

dt_siRNA <- fread(input = "Cherry_Pick_Worklist.csv")

setnames(dt_siRNA, c("dest_col", 
                  "dest_row",
                  "dest_well"), 
                c("Column",
                  "Row",
                  "WellName"))

glimpse(dt_siRNA)
Rows: 340
Columns: 17
$ .id            <chr> "LP_48199 G-CUSTOM-366598.csv", "LP_48199 G-CUSTOM-…
$ source_rack    <chr> "Plate 1", "Plate 1", "Plate 1", "Plate 1", "Plate …
$ source_well    <chr> "A02", "B02", "C02", "D02", "E02", "F02", "G02", "H…
$ oligo_id       <chr> "D-009329-01", "D-003477-18", "D-011653-01", "D-007…
$ gene_symbol    <chr> "ACAA1", "CREBBP", "EYA3", "SLC22A18", "RPA3", "TP5…
$ gene_id        <int> 30, 1387, 2140, 5002, 6119, 7158, 8520, 9631, 30, 1…
$ gene_accession <chr> "NM_001607", "NM_001079846", "NM_001990", "NM_00255…
$ gi_number      <int> 6598316, 119943101, 26667242, 34734074, 52851430, 5…
$ sequence       <chr> "GAGAUUGCCUGAUUCCUAU", "UCACAGAGAUCCAGGGCGA", "GAUU…
$ source_pos     <int> 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, …
$ source_col     <int> 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, …
$ source_row     <int> 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, …
$ source_row2    <chr> "A", "B", "C", "D", "E", "F", "G", "H", "A", "B", "…
$ dest_pos       <int> 84, 72, 340, 225, 89, 66, 87, 221, 254, 127, 30, 44…
$ Column         <int> 6, 5, 22, 15, 6, 5, 6, 14, 16, 8, 2, 3, 11, 18, 1, …
$ Row            <int> 4, 8, 4, 1, 9, 2, 7, 13, 14, 15, 14, 12, 8, 14, 5, …
$ WellName       <chr> "D6", "H5", "D22", "A15", "I6", "B5", "G6", "M14", …

Create a control layout data.table that contains the positions of the library (sample), empty wells (empty), and controls (negative, positive1 or LMNB1, positive2 or SYNE2, positive3 or LMNA, and killer).

dt_control <- data.table(Column = rep(1:24, each = 16), Row = rep(1:16, 24))
dt_control[, WellName := paste0(LETTERS[Row], Column)]
dt_control[Column %in% 1:21, treatment := "sample"]
dt_control[Column == 22 & Row %in% 1:4, treatment := "sample"]
dt_control[Column == 22 & Row %in% 5:12, treatment := "LMNA"]
dt_control[Column == 22 & Row %in% 13:16, treatment := "empty"]
dt_control[Column %in% 23 & Row %in% seq(1, 16, 2), treatment := "negative"]
dt_control[Column %in% 23 & Row %in% seq(2, 16, 2), treatment := "killer"]
dt_control[Column %in% 24 & Row %in% seq(1, 16, 2), treatment := "LMNB1"]
dt_control[Column %in% 24 & Row %in% seq(2, 16, 2), treatment := "SYNE2"]

glimpse(dt_control)
Rows: 384
Columns: 4
$ Column    <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,…
$ Row       <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1…
$ WellName  <chr> "A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1", "I1", "J…
$ treatment <chr> "sample", "sample", "sample", "sample", "sample", "sampl…

Merge the control layout and the siRNA layout data.tables.

dt_layout <- dt_siRNA[dt_control, on = c("Column", "Row")]

dt_layout

Read and process the Columbus data

Set RegEx patterns for directory searches for logs file data and spot data on a per protocol step basis.

pat_col <- "*.result\\.1\\.txt"# Pattern for Columbus results files

Create a list of the RegEx patterns set in the previous chunk. Important: the list names will be carried over all the next steps!!!

pat_list <- list(col = pat_col)

pat_list

Recursively search the working directory and its subdirectories for files whose name includes the RegEx patterns defined two chunks above. The path_list functon outputs absolute file names. path_list is a list containing all the filenames on a per Janus step basis.

list_files <- function(x){
  dir(path = "input", pattern = x, full.names = TRUE, recursive = TRUE, include.dirs = TRUE)
}

path_list <- llply(pat_list, list_files) 

path_list

Extract file names from absolute path and set them as list element names.

trim_names <- function(x){
  names(x) <- basename(x) # This assigns the filename to the file that it is read
  y <- x ## This is necessary because of scoping issues
}

path_list <- llply(path_list, trim_names) 

Recursively read and merge object level data files as data.frames. Rows are labeled with relative filenames (The .id variable). This and the previous chunks are slightly modified tricks adopted from H. Wickam “Tidy Data” paper.

read_merge <- function(x){
  dt <-as.data.table(ldply(x, fread, integer64 = "character")) 
}

dt_list <- llply(path_list, read_merge)

Separate Columbus data from the other classes of data.

dt_col <- dt_list$col

rm(dt_list)

glimpse(dt_col)
Rows: 768
Columns: 22
$ .id                                                                        <chr> …
$ ScreenName                                                                 <chr> …
$ ScreenID                                                                   <int> …
$ PlateName                                                                  <chr> …
$ PlateID                                                                    <int> …
$ MeasurementDate                                                            <dttm> …
$ MeasurementID                                                              <int> …
$ WellName                                                                   <chr> …
$ Row                                                                        <int> …
$ Column                                                                     <int> …
$ Timepoint                                                                  <int> …
$ Plane                                                                      <int> …
$ `Nuclei Selected - Number of Objects`                                      <int> …
$ `Nuclei Selected - Nucleus Area [µm²] - Mean per Well`                     <dbl> …
$ `Nuclei Selected - Nucleus Roundness - Mean per Well`                      <dbl> …
$ `Nuclei Selected - Nucleus Width [µm] - Mean per Well`                     <dbl> …
$ `Nuclei Selected - Nucleus Length [µm] - Mean per Well`                    <dbl> …
$ `Nuclei Selected - Nucleus Ratio Width to Length - Mean per Well`          <dbl> …
$ `Nuclei Selected - Intensity Nucleus Region Exp2Cam1 Mean - Mean per Well` <dbl> …
$ `Nuclei Selected - Intensity Nucleus Region Exp3Cam2 Mean - Mean per Well` <dbl> …
$ `Number of Analyzed Fields`                                                <int> …
$ Link                                                                       <chr> …

Rename variables

setnames(dt_col, c("Nuclei Selected - Number of Objects",
                   "Nuclei Selected - Nucleus Area [µm²] - Mean per Well",
                   "Nuclei Selected - Nucleus Roundness - Mean per Well",
                   "Nuclei Selected - Intensity Nucleus Region Exp2Cam1 Mean - Mean per Well",
                   "Nuclei Selected - Intensity Nucleus Region Exp3Cam2 Mean - Mean per Well"),
                 c("cell_number",
                   "nuc_area",
                   "nuc_roundness",
                   "nuc_green_int",
                   "nuc_red_int"))

glimpse(dt_col)
Rows: 768
Columns: 22
$ .id                                                               <chr> …
$ ScreenName                                                        <chr> …
$ ScreenID                                                          <int> …
$ PlateName                                                         <chr> …
$ PlateID                                                           <int> …
$ MeasurementDate                                                   <dttm> …
$ MeasurementID                                                     <int> …
$ WellName                                                          <chr> …
$ Row                                                               <int> …
$ Column                                                            <int> …
$ Timepoint                                                         <int> …
$ Plane                                                             <int> …
$ cell_number                                                       <int> …
$ nuc_area                                                          <dbl> …
$ nuc_roundness                                                     <dbl> …
$ `Nuclei Selected - Nucleus Width [µm] - Mean per Well`            <dbl> …
$ `Nuclei Selected - Nucleus Length [µm] - Mean per Well`           <dbl> …
$ `Nuclei Selected - Nucleus Ratio Width to Length - Mean per Well` <dbl> …
$ nuc_green_int                                                     <dbl> …
$ nuc_red_int                                                       <dbl> …
$ `Number of Analyzed Fields`                                       <int> …
$ Link                                                              <chr> …

Merge the Columbus measurements data with the layout data.

dt_data <- dt_col[dt_layout, on = c("Column", "Row")]

glimpse(dt_data)
Rows: 768
Columns: 39
$ .id                                                               <chr> …
$ ScreenName                                                        <chr> …
$ ScreenID                                                          <int> …
$ PlateName                                                         <chr> …
$ PlateID                                                           <int> …
$ MeasurementDate                                                   <dttm> …
$ MeasurementID                                                     <int> …
$ WellName                                                          <chr> …
$ Row                                                               <int> …
$ Column                                                            <int> …
$ Timepoint                                                         <int> …
$ Plane                                                             <int> …
$ cell_number                                                       <int> …
$ nuc_area                                                          <dbl> …
$ nuc_roundness                                                     <dbl> …
$ `Nuclei Selected - Nucleus Width [µm] - Mean per Well`            <dbl> …
$ `Nuclei Selected - Nucleus Length [µm] - Mean per Well`           <dbl> …
$ `Nuclei Selected - Nucleus Ratio Width to Length - Mean per Well` <dbl> …
$ nuc_green_int                                                     <dbl> …
$ nuc_red_int                                                       <dbl> …
$ `Number of Analyzed Fields`                                       <int> …
$ Link                                                              <chr> …
$ i..id                                                             <chr> …
$ source_rack                                                       <chr> …
$ source_well                                                       <chr> …
$ oligo_id                                                          <chr> …
$ gene_symbol                                                       <chr> …
$ gene_id                                                           <int> …
$ gene_accession                                                    <chr> …
$ gi_number                                                         <int> …
$ sequence                                                          <chr> …
$ source_pos                                                        <int> …
$ source_col                                                        <int> …
$ source_row                                                        <int> …
$ source_row2                                                       <chr> …
$ dest_pos                                                          <int> …
$ i.WellName                                                        <chr> …
$ i.WellName.1                                                      <chr> …
$ treatment                                                         <chr> …

Plot the data

Quite a few wells in HTIF00183 clearly had an issue, either due to the sample itself, or to the autofocus. For this reason, these wells will be eliminated from the analysis.


excluded <- c("M7", "N7", "O7", "P7", "O8", "P8")

dt_data <- dt_data[!(PlateName == "HTIF00183" & WellName %in% excluded),]

Calculate the mean and standard devitation (SD) for the negative control siRNA on a per plate basis.

dt_norm <-
    dt_data[treatment == "negative", .(
    neg_n_cells_mean = mean(cell_number, na.rm = TRUE),
    neg_n_cells_sd = sd(cell_number, na.rm = TRUE),
    neg_area_mean = mean(nuc_area, na.rm = TRUE),
    neg_area_sd = sd(nuc_area, na.rm = TRUE),
    neg_round_mean = mean(nuc_roundness, na.rm = TRUE),
    neg_round_sd = sd(nuc_roundness, na.rm = TRUE),
    neg_nuc_red_mean = mean(nuc_red_int, na.rm = TRUE),
    neg_nuc_red_sd = sd(nuc_red_int, na.rm = TRUE),
    neg_nuc_green_mean = mean(nuc_green_int, na.rm = TRUE),
    neg_nuc_green_sd = sd(nuc_green_int, na.rm = TRUE)
    ), by = .id]

glimpse(dt_norm)
Rows: 2
Columns: 11
$ .id                <chr> "Shape_Size_Intensity_hEpigenetics_Val[159522].…
$ neg_n_cells_mean   <dbl> 403.125, 308.375
$ neg_n_cells_sd     <dbl> 48.40141, 29.04645
$ neg_area_mean      <dbl> 192.2003, 192.9557
$ neg_area_sd        <dbl> 6.202427, 4.306389
$ neg_round_mean     <dbl> 0.9634322, 0.9740030
$ neg_round_sd       <dbl> 0.004896193, 0.002212123
$ neg_nuc_red_mean   <dbl> 251.4881, 309.4958
$ neg_nuc_red_sd     <dbl> 37.80239, 15.59650
$ neg_nuc_green_mean <dbl> 1189.074, 1411.724
$ neg_nuc_green_sd   <dbl> 257.6809, 142.6345

Calculate Z-scores based on the mean and SD of the negative controls. Also calculate the negative control normalized values (On a per plate basis).

dt_data <- dt_data[dt_norm, on = ".id"]

z_score <- function(measurement, average, s_dev){
           return((measurement - average)/s_dev)
}

norm_change <-function(measurement, average){
            return(100*(measurement/average))
}

dt_data[, `:=`(n_cells_z_score = z_score(cell_number, neg_n_cells_mean, neg_n_cells_sd),
               n_cells_norm_change = norm_change(cell_number, neg_n_cells_mean),
               area_z_score = z_score(nuc_area, neg_area_mean, neg_area_sd),
               area_norm_change = norm_change(nuc_area, neg_area_mean),
               round_z_score = z_score(nuc_roundness, neg_round_mean, neg_round_sd),
               round_norm_change = norm_change(nuc_roundness, neg_round_mean),
               nuc_red_z_score = z_score(nuc_red_int, neg_nuc_red_mean, neg_nuc_red_sd),
               nuc_red_norm_change = norm_change(nuc_red_int, neg_nuc_red_mean),
               nuc_green_z_score = z_score(nuc_green_int, neg_nuc_green_mean, neg_nuc_green_sd),
               nuc_green_norm_change = norm_change(nuc_green_int, neg_nuc_green_mean))]

glimpse(dt_data)
Rows: 762
Columns: 59
$ .id                                                               <chr> …
$ ScreenName                                                        <chr> …
$ ScreenID                                                          <int> …
$ PlateName                                                         <chr> …
$ PlateID                                                           <int> …
$ MeasurementDate                                                   <dttm> …
$ MeasurementID                                                     <int> …
$ WellName                                                          <chr> …
$ Row                                                               <int> …
$ Column                                                            <int> …
$ Timepoint                                                         <int> …
$ Plane                                                             <int> …
$ cell_number                                                       <int> …
$ nuc_area                                                          <dbl> …
$ nuc_roundness                                                     <dbl> …
$ `Nuclei Selected - Nucleus Width [µm] - Mean per Well`            <dbl> …
$ `Nuclei Selected - Nucleus Length [µm] - Mean per Well`           <dbl> …
$ `Nuclei Selected - Nucleus Ratio Width to Length - Mean per Well` <dbl> …
$ nuc_green_int                                                     <dbl> …
$ nuc_red_int                                                       <dbl> …
$ `Number of Analyzed Fields`                                       <int> …
$ Link                                                              <chr> …
$ i..id                                                             <chr> …
$ source_rack                                                       <chr> …
$ source_well                                                       <chr> …
$ oligo_id                                                          <chr> …
$ gene_symbol                                                       <chr> …
$ gene_id                                                           <int> …
$ gene_accession                                                    <chr> …
$ gi_number                                                         <int> …
$ sequence                                                          <chr> …
$ source_pos                                                        <int> …
$ source_col                                                        <int> …
$ source_row                                                        <int> …
$ source_row2                                                       <chr> …
$ dest_pos                                                          <int> …
$ i.WellName                                                        <chr> …
$ i.WellName.1                                                      <chr> …
$ treatment                                                         <chr> …
$ neg_n_cells_mean                                                  <dbl> …
$ neg_n_cells_sd                                                    <dbl> …
$ neg_area_mean                                                     <dbl> …
$ neg_area_sd                                                       <dbl> …
$ neg_round_mean                                                    <dbl> …
$ neg_round_sd                                                      <dbl> …
$ neg_nuc_red_mean                                                  <dbl> …
$ neg_nuc_red_sd                                                    <dbl> …
$ neg_nuc_green_mean                                                <dbl> …
$ neg_nuc_green_sd                                                  <dbl> …
$ n_cells_z_score                                                   <dbl> …
$ n_cells_norm_change                                               <dbl> …
$ area_z_score                                                      <dbl> …
$ area_norm_change                                                  <dbl> …
$ round_z_score                                                     <dbl> …
$ round_norm_change                                                 <dbl> …
$ nuc_red_z_score                                                   <dbl> …
$ nuc_red_norm_change                                               <dbl> …
$ nuc_green_z_score                                                 <dbl> …
$ nuc_green_norm_change                                             <dbl> …

Write the data to a .csv file for further analysis

write.table(dt_data, 
            paste("output/validation", red_name, green_name, "normalized_results.txt", sep = "_"),
            quote = FALSE,
            sep = "\t",
            row.names = FALSE, 
            col.names = TRUE)

Create a novel unique identifier for each oligo that contains also the gene symbol.

dt_data[,oligo_name := paste(gene_symbol, str_extract(oligo_id, "[0-9]{2}$"), sep = "-")]
ℹ The package "Hmisc" is required.
✖ Would you like to install it?

1: Yes
2: No

Enter an item from the menu, or 0 to exit
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.2/checkmate_2.1.0.tgz'
Content type 'application/x-gzip' length 702523 bytes (686 KB)
==================================================
downloaded 686 KB

trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.2/htmlwidgets_1.6.2.tgz'
Content type 'application/x-gzip' length 803214 bytes (784 KB)
==================================================
downloaded 784 KB

trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.2/htmlTable_2.4.1.tgz'
Content type 'application/x-gzip' length 419727 bytes (409 KB)
==================================================
downloaded 409 KB

trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.2/Formula_1.2-5.tgz'
Content type 'application/x-gzip' length 158153 bytes (154 KB)
==================================================
downloaded 154 KB

trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.2/Hmisc_5.0-1.tgz'
Content type 'application/x-gzip' length 3434580 bytes (3.3 MB)
==================================================
downloaded 3.3 MB

The downloaded binary packages are in
    /var/folders/lp/2jhntvmx27z1mlsyhx8xpmwhfr_62q/T//Rtmp86jG8C/downloaded_packages

Aggregate the biological repeats (The two different plates) by calculating the mean and SD for all the variables (Z-scores and fold changes). n = 2.

dt_aggregated <- dt_data %>% 
        group_by(gene_symbol,
                 gene_id,
                 oligo_id,
                 oligo_name,
                 sequence) %>%
        summarise(across(n_cells_z_score:nuc_green_norm_change, list(mean, sd))) %>%
        arrange(oligo_name)
`summarise()` has grouped output by 'gene_symbol', 'gene_id', 'oligo_id', 'oligo_name'. You can override using the `.groups` argument.
write.table(dt_aggregated, 
            paste("output/validation", red_name, green_name, "aggregated_results.txt", sep = "_"),
            quote = FALSE,
            sep = "\t",
            row.names = FALSE, 
            col.names = TRUE)

Document the information about the analysis session

sessionInfo()
LS0tCnRpdGxlOiAiU2Vjb25kYXJ5IHNpUk5BIFNjcmVlbiBWYWxpZGF0aW9uIC0gTE1OQS9MTU5CIgphdXRob3I6ICJBbmRyaWEgU2NoaWJsZXIvR2lhbmx1Y2EgUGVnb3Jhcm8iCmRhdGU6ICJNYXJjaCAyN3RoIDIwMjMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCiMjIyBJbnRyb2R1Y3Rpb24KClRoaXMgc2NyaXB0IGlzIHVzZWQgdG8gYW5hbHl6ZSBzaVJOQSBzY3JlZW4gdmFsaWRhdGlvbiBkYXRhIG9idGFpbmVkIHdpdGggSGlnaC1Db250ZW50IEltYWdlIGFuYWx5c2lzLiBJbiBwYXJ0aWN1bGFyLCB0aGUgc2lSTkEgbGlicmFyeSB1c2VkIGlzIHRoZSBEaGFybWFjb24gZ2VuZXJhdGVkIGJ5IEFuZHJpYSBTY2hpYmxlciBhbmQgUGVkamEgSmV2dGljLCBiYXNlZCBvbiB0aGUgcHJpbWFyeSBzaVJOQSBzY3JlZW4gcmVzdWx0cyB1c2luZyB0aGUgRXBpZ2VuZXRpY3MgYW5kIEN1c3RvbSBOdWNsZWFyIEVudmVsb3BlIGxpYnJhcmllcyBmcm9tIFRoZXJtb0Zpc2hlci4KClRoZSBzaVJOQSBsaWJyYXJ5IHdhcyBvcmlnaW5hbGx5IHJlY2VpdmVkIGRyaWVkIGluIDk2IHdlbGwgcGxhdGVzIGF0IDAuMjUgbk0uIEl0IHdhcyByZXN1c3BlbmRlZCBhbmQgbWl4ZWQgaW4gNTAgdWwgbnVjbGVhc2UtZnJlZSB3YXRlciB0byBvYnRhaW4gYSBmaW5hbCBjb25jZW50cmF0aW9uIG9mIDUgdU0sIGZyb3plbiBvdmVybmlnaHQgYW5kIHRoZW4gdGhhd2VkIHRvIGluY3JlYXNlIG9saWdvIHNpUk5BIHNvbHViaWxpdHkuNDUgdWwgd2VyZSBhc3BpcmF0ZWQgZnJvbSB0aGUgb3JpZ2luYWwgc291cmNlIHBsYXRlIGFuZCBkaXNwZW5zZWQgaW50byBzZXBhcmF0ZSB3ZWxscyB0byBnZW5lcmF0ZSBhIDM4NCB3ZWxsIG1hc3RlciBQbGF0ZS4gVGhlc2Ugc2lSTkFzIG9jY3VwaWVkIGNvbHVtbnMgMSB0byAyMiAoUGFydGlhbCkuIEFsbCB0aGVzZSBsaXF1aWQgaGFuZGxpbmcgb3BlcmF0aW9ucyB3ZXJlIHBlcmZvcm1lZCB1c2luZyBhIFBlcmtpbkVsbWVyIEphbnVzIGluc3RydW1lbnQsIHdoaWNoIG91dHB1dCBhbGwgdGhlIGxpcXVpZCBoYW5kbGluZyBvcGVyYXRpb25zIGxvZ3MgYXMgdGV4dCBmaWxlcy4zODQgd2VsbCBpbWFnaW5nIHJlYWR5IHBsYXRlcyBjb250YWluaW5nIHNwb3R0ZWQgc2lSTkEgKDMwMCBubCkgd2VyZSBnZW5lcmF0ZWQgdXNpbmcgYW4gRWNobzUyNS4gMzAwIG9mIHVsIGNvbnRyb2wgc2lSTkEgKDV1TSkgd2VyZSB0aGVuIGFkZGVkIHRvIHRoZWlyIHJlc3BlY3RpdmUgd2VsbHMgaW4gY29sdW1ucyAyMiwgMjMgYW5kIDI0LiBUaGUgaW1hZ2luZyBhc3NheSByZWFkeSBwbGF0ZXMgd2VyZSBzZWFsZWQgd2l0aCBhbHVtaW51bSBzZWFsaW5nIGZvaWwgYW5kIHN0b3JlZCBhdCAtMjBvQyB1bnRpbCB1c2UuCgpJbWFnaW5nIEFzc2F5IHBsYXRlcyB3ZXJlIGRyaWVkLCBmcm96ZW4gYW5kIHRoZW4gdXNlZCBpbiByZXZlcnNlIHRyYW5zZmVjdGlvbiBleHBlcmltZW50cy4gRm9yIHJldmVyZXNlIHRyYW5zZmVjdGlvbiwgcGxhdGVzIHdlcmUgdGhhd2VkLCBzcGlubmVkIGFuZCAyMCB1bCBvZiBPcHRpbWVtICsgMC4wNSB1bC93ZWxsIG9mIFJOQWlNYXggd2VyZSBhZGRlZCB0byB0aGUgcGxhdGVzIGFuZCBpbmN1YmF0ZWQgZm9yIDMwJy4gVGhlbiAyMCB1bCBvZiBjZWxscyB3ZXJlIGFkZGVkIG9uIHRvcCBvZiB0aGUgc2lSTkEvUk5BaU1heCBtaXggYW5kIGluY3ViYXRlZCBmb3IgNzIgaHJzLgoKRml4ZWQgYW5kIHN0YWluZWQgcGxhdGVzIHdlcmUgaW1hZ2VkIG9uIGFuIE9wZXJhIFFFSFMgbWljcm9zY29wZSB1c2luZyBhIDQwWCB3YXRlciBpbW1lcnNpb24gb2JqZWN0aXZlcy4gSW1hZ2VzIHdlcmUgYW5hbHl6ZWQgaW4gQ29sdW1idXMgMi44LjEsIGFuZCBpbWFnZSBhbmFseXNpcyByZXN1bHRzIHdlcmUgZXhwb3J0ZWQgYXMgdGFiIGRlbGltaXRlZCAudHh0IGZpbGVzLgoKVGhlIHNjcmlwdCByZWFkcyBsaWJyYXJ5IHJlZm9ybWF0dGluZyBmaWxlcyB1c2VkIG9uIHRoZSBFY2hvIChDb250YWluaW5nIHRoZSBzaVJOQSBsYXlvdXQpLCB0aGUgQ29sdW1idXMgaW1hZ2UgYW5hbHlzaXMgcmVzdWx0cyBhbmQgZ2VuZXJhdGVzIHN0YXRpc3RpY2FsIGFuYWx5c2lzLgoKIyMjIEFiIG1hcmtlcnM6CgotICAgR3JlZW46IExNTkIKLSAgIFJlZDogTE1OQQoKIyMjIExvYWQgcGFja2FnZXMuCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KbGlicmFyeShwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShrbml0cikKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHZpcmlkaXMpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cm9wdHNfY2h1bmskc2V0KAogICAgZmlnLnBhdGggPSAib3V0cHV0LyIsCiAgICBjYWNoZSA9IEZBTFNFLAogICAgZmlnLndpZHRoID0gMTUsCiAgICBmaWcuaGVpZ2h0ID0gNywKICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgIHdhcm5pbmcgPSBGQUxTRQogICAgKQpgYGAKCmBgYHtyIHNldFRoZW1lYW5kUGFsZXR0ZSwgaW5jbHVkZT0nZmFsc2UnfQp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQp0aGVtZV91cGRhdGUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gLTkwLCBoanVzdCA9IDAsIHZqdXN0ID0gMC41KSkKYGBgCgojIyMgUmVhZCB0aGUgc2lSTkEgbGF5b3V0cyBhbmQgZ2VuZXJhdGUgYSBjb250cm9sIGxheW91dAoKU2V0IGNoYW5uZWwgdmFyaWFibGUgbmFtZXMuCgpgYGB7cn0KZ3JlZW5fbmFtZSA9ICJMTU5CIgpyZWRfbmFtZSA9ICJMTU5BIgpgYGAKClJlYWQgdGhlIHNpUk5BIGxheW91dCBpbmZvcm1hdGlvbiBwcm92aWRlZCBieSBEaGFybWFjb24gYW5kIHNlbGVjdCBvbmx5IHJlbGV2YW50IGNvbHVtbnMuIFRoZSBjdXN0b20gY2hlcnJ5IHBpY2sgd29yayBsaXN0IGZpbGUgdGhhdCB3YXMgZ2VuZXJhdGVkIGJ5IHRoZSBKYW51cyB0byByZWZvcm1hdCB0aGUgc2lSTkEgb2xpZ29zIGZyb20gOTYgd2VsbCB0byAzODQuCgpgYGB7ciBnZW5lTGlzdFJlYWR9CmR0X3NpUk5BIDwtIGZyZWFkKGlucHV0ID0gIkNoZXJyeV9QaWNrX1dvcmtsaXN0LmNzdiIpCgpzZXRuYW1lcyhkdF9zaVJOQSwgYygiZGVzdF9jb2wiLCAKICAgICAgICAgICAgICAgICAgImRlc3Rfcm93IiwKICAgICAgICAgICAgICAgICAgImRlc3Rfd2VsbCIpLCAKICAgICAgICAgICAgICAgIGMoIkNvbHVtbiIsCiAgICAgICAgICAgICAgICAgICJSb3ciLAogICAgICAgICAgICAgICAgICAiV2VsbE5hbWUiKSkKCmdsaW1wc2UoZHRfc2lSTkEpCmBgYAoKQ3JlYXRlIGEgY29udHJvbCBsYXlvdXQgZGF0YS50YWJsZSB0aGF0IGNvbnRhaW5zIHRoZSBwb3NpdGlvbnMgb2YgdGhlIGxpYnJhcnkgKGBzYW1wbGVgKSwgZW1wdHkgd2VsbHMgKGBlbXB0eWApLCBhbmQgY29udHJvbHMgKGBuZWdhdGl2ZWAsIGBwb3NpdGl2ZTFgIG9yIExNTkIxLCBgcG9zaXRpdmUyYCBvciBTWU5FMiwgYHBvc2l0aXZlM2Agb3IgTE1OQSwgYW5kIGBraWxsZXJgKS4KCmBgYHtyIGNvbnRyb2xMYXlvdXR9CmR0X2NvbnRyb2wgPC0gZGF0YS50YWJsZShDb2x1bW4gPSByZXAoMToyNCwgZWFjaCA9IDE2KSwgUm93ID0gcmVwKDE6MTYsIDI0KSkKZHRfY29udHJvbFssIFdlbGxOYW1lIDo9IHBhc3RlMChMRVRURVJTW1Jvd10sIENvbHVtbildCmR0X2NvbnRyb2xbQ29sdW1uICVpbiUgMToyMSwgdHJlYXRtZW50IDo9ICJzYW1wbGUiXQpkdF9jb250cm9sW0NvbHVtbiA9PSAyMiAmIFJvdyAlaW4lIDE6NCwgdHJlYXRtZW50IDo9ICJzYW1wbGUiXQpkdF9jb250cm9sW0NvbHVtbiA9PSAyMiAmIFJvdyAlaW4lIDU6MTIsIHRyZWF0bWVudCA6PSAiTE1OQSJdCmR0X2NvbnRyb2xbQ29sdW1uID09IDIyICYgUm93ICVpbiUgMTM6MTYsIHRyZWF0bWVudCA6PSAiZW1wdHkiXQpkdF9jb250cm9sW0NvbHVtbiAlaW4lIDIzICYgUm93ICVpbiUgc2VxKDEsIDE2LCAyKSwgdHJlYXRtZW50IDo9ICJuZWdhdGl2ZSJdCmR0X2NvbnRyb2xbQ29sdW1uICVpbiUgMjMgJiBSb3cgJWluJSBzZXEoMiwgMTYsIDIpLCB0cmVhdG1lbnQgOj0gImtpbGxlciJdCmR0X2NvbnRyb2xbQ29sdW1uICVpbiUgMjQgJiBSb3cgJWluJSBzZXEoMSwgMTYsIDIpLCB0cmVhdG1lbnQgOj0gIkxNTkIxIl0KZHRfY29udHJvbFtDb2x1bW4gJWluJSAyNCAmIFJvdyAlaW4lIHNlcSgyLCAxNiwgMiksIHRyZWF0bWVudCA6PSAiU1lORTIiXQoKZ2xpbXBzZShkdF9jb250cm9sKQpgYGAKCk1lcmdlIHRoZSBjb250cm9sIGxheW91dCBhbmQgdGhlIHNpUk5BIGxheW91dCBkYXRhLnRhYmxlcy4KCmBgYHtyIHNpUk5BQ29udHJvbE1lcmdlfQpkdF9sYXlvdXQgPC0gZHRfc2lSTkFbZHRfY29udHJvbCwgb24gPSBjKCJDb2x1bW4iLCAiUm93IildCgpkdF9sYXlvdXQKYGBgCgojIyMgUmVhZCBhbmQgcHJvY2VzcyB0aGUgQ29sdW1idXMgZGF0YQoKU2V0IFJlZ0V4IHBhdHRlcm5zIGZvciBkaXJlY3Rvcnkgc2VhcmNoZXMgZm9yIGxvZ3MgZmlsZSBkYXRhIGFuZCBzcG90IGRhdGEgb24gYSBwZXIgcHJvdG9jb2wgc3RlcCBiYXNpcy4KCmBgYHtyIHJlZ2V4RmlsZW5hbWV9CnBhdF9jb2wgPC0gIioucmVzdWx0XFwuMVxcLnR4dCIjIFBhdHRlcm4gZm9yIENvbHVtYnVzIHJlc3VsdHMgZmlsZXMKYGBgCgpDcmVhdGUgYSBsaXN0IG9mIHRoZSBSZWdFeCBwYXR0ZXJucyBzZXQgaW4gdGhlIHByZXZpb3VzIGNodW5rLiAqKkltcG9ydGFudDoqKiB0aGUgbGlzdCBuYW1lcyB3aWxsIGJlIGNhcnJpZWQgb3ZlciBhbGwgdGhlIG5leHQgc3RlcHMhISEKCi0gICBjb2wgPSBDb2x1bWJ1cyBkYXRhCgpgYGB7ciBwYXRMaXN0LCByZXN1bHRzID0gJ2hpZGUnfQpwYXRfbGlzdCA8LSBsaXN0KGNvbCA9IHBhdF9jb2wpCgpwYXRfbGlzdApgYGAKClJlY3Vyc2l2ZWx5IHNlYXJjaCB0aGUgd29ya2luZyBkaXJlY3RvcnkgYW5kIGl0cyBzdWJkaXJlY3RvcmllcyBmb3IgZmlsZXMgd2hvc2UgbmFtZSBpbmNsdWRlcyB0aGUgUmVnRXggcGF0dGVybnMgZGVmaW5lZCB0d28gY2h1bmtzIGFib3ZlLiBUaGUgYHBhdGhfbGlzdGAgZnVuY3RvbiBvdXRwdXRzIGFic29sdXRlIGZpbGUgbmFtZXMuIGBwYXRoX2xpc3RgIGlzIGEgbGlzdCBjb250YWluaW5nIGFsbCB0aGUgZmlsZW5hbWVzIG9uIGEgcGVyIEphbnVzIHN0ZXAgYmFzaXMuCgpgYGB7ciBkaXJlY3RvcnlTZWFyY2gsIHJlc3VsdHM9J2hpZGUnfQpsaXN0X2ZpbGVzIDwtIGZ1bmN0aW9uKHgpewogIGRpcihwYXRoID0gImlucHV0IiwgcGF0dGVybiA9IHgsIGZ1bGwubmFtZXMgPSBUUlVFLCByZWN1cnNpdmUgPSBUUlVFLCBpbmNsdWRlLmRpcnMgPSBUUlVFKQp9CgpwYXRoX2xpc3QgPC0gbGxwbHkocGF0X2xpc3QsIGxpc3RfZmlsZXMpIAoKcGF0aF9saXN0CmBgYAoKRXh0cmFjdCBmaWxlIG5hbWVzIGZyb20gYWJzb2x1dGUgcGF0aCBhbmQgc2V0IHRoZW0gYXMgbGlzdCBlbGVtZW50IG5hbWVzLgoKYGBge3IgdHJpbU5hbWVzLCByZXN1bHRzPSdoaWRlJ30KdHJpbV9uYW1lcyA8LSBmdW5jdGlvbih4KXsKICBuYW1lcyh4KSA8LSBiYXNlbmFtZSh4KSAjIFRoaXMgYXNzaWducyB0aGUgZmlsZW5hbWUgdG8gdGhlIGZpbGUgdGhhdCBpdCBpcyByZWFkCiAgeSA8LSB4ICMjIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2Ugb2Ygc2NvcGluZyBpc3N1ZXMKfQoKcGF0aF9saXN0IDwtIGxscGx5KHBhdGhfbGlzdCwgdHJpbV9uYW1lcykgCmBgYAoKUmVjdXJzaXZlbHkgcmVhZCBhbmQgbWVyZ2Ugb2JqZWN0IGxldmVsIGRhdGEgZmlsZXMgYXMgZGF0YS5mcmFtZXMuIFJvd3MgYXJlIGxhYmVsZWQgd2l0aCByZWxhdGl2ZSBmaWxlbmFtZXMgKFRoZSBgLmlkYCB2YXJpYWJsZSkuIFRoaXMgYW5kIHRoZSBwcmV2aW91cyBjaHVua3MgYXJlIHNsaWdodGx5IG1vZGlmaWVkIHRyaWNrcyBhZG9wdGVkIGZyb20gSC4gV2lja2FtIFsiVGlkeSBEYXRhIiBwYXBlcl0oaHR0cDovL3ZpdGEuaGFkLmNvLm56L3BhcGVycy90aWR5LWRhdGEucGRmKS4KCmBgYHtyIHJlYWRNZXJnZSwgcmVzdWx0cz0naGlkZScsIHdhcm5pbmc9Rn0KcmVhZF9tZXJnZSA8LSBmdW5jdGlvbih4KXsKICBkdCA8LWFzLmRhdGEudGFibGUobGRwbHkoeCwgZnJlYWQsIGludGVnZXI2NCA9ICJjaGFyYWN0ZXIiKSkgCn0KCmR0X2xpc3QgPC0gbGxwbHkocGF0aF9saXN0LCByZWFkX21lcmdlKQpgYGAKClNlcGFyYXRlIENvbHVtYnVzIGRhdGEgZnJvbSB0aGUgb3RoZXIgY2xhc3NlcyBvZiBkYXRhLgoKYGBge3Igc2VwYXJhdGVDb2x1bWJ1c0RhdGF9CmR0X2NvbCA8LSBkdF9saXN0JGNvbAoKcm0oZHRfbGlzdCkKCmdsaW1wc2UoZHRfY29sKQpgYGAKClJlbmFtZSB2YXJpYWJsZXMKCmBgYHtyfQpzZXRuYW1lcyhkdF9jb2wsIGMoIk51Y2xlaSBTZWxlY3RlZCAtIE51bWJlciBvZiBPYmplY3RzIiwKICAgICAgICAgICAgICAgICAgICJOdWNsZWkgU2VsZWN0ZWQgLSBOdWNsZXVzIEFyZWEgW8K1bcKyXSAtIE1lYW4gcGVyIFdlbGwiLAogICAgICAgICAgICAgICAgICAgIk51Y2xlaSBTZWxlY3RlZCAtIE51Y2xldXMgUm91bmRuZXNzIC0gTWVhbiBwZXIgV2VsbCIsCiAgICAgICAgICAgICAgICAgICAiTnVjbGVpIFNlbGVjdGVkIC0gSW50ZW5zaXR5IE51Y2xldXMgUmVnaW9uIEV4cDJDYW0xIE1lYW4gLSBNZWFuIHBlciBXZWxsIiwKICAgICAgICAgICAgICAgICAgICJOdWNsZWkgU2VsZWN0ZWQgLSBJbnRlbnNpdHkgTnVjbGV1cyBSZWdpb24gRXhwM0NhbTIgTWVhbiAtIE1lYW4gcGVyIFdlbGwiKSwKICAgICAgICAgICAgICAgICBjKCJjZWxsX251bWJlciIsCiAgICAgICAgICAgICAgICAgICAibnVjX2FyZWEiLAogICAgICAgICAgICAgICAgICAgIm51Y19yb3VuZG5lc3MiLAogICAgICAgICAgICAgICAgICAgIm51Y19ncmVlbl9pbnQiLAogICAgICAgICAgICAgICAgICAgIm51Y19yZWRfaW50IikpCgpnbGltcHNlKGR0X2NvbCkKYGBgCgpNZXJnZSB0aGUgQ29sdW1idXMgbWVhc3VyZW1lbnRzIGRhdGEgd2l0aCB0aGUgbGF5b3V0IGRhdGEuCgpgYGB7ciByZXN1bHRzTGF5b3V0TWVyZ2V9CmR0X2RhdGEgPC0gZHRfY29sW2R0X2xheW91dCwgb24gPSBjKCJDb2x1bW4iLCAiUm93IildCgpnbGltcHNlKGR0X2RhdGEpCmBgYAoKIyBQbG90IHRoZSBkYXRhCgpgYGB7ciBsYXlvdXRQbG90LCBlY2hvPUZBTFNFfQpsYXlvdXRfcGxvdCA8LSBnZ3Bsb3QoZHRfZGF0YSwgYWVzKHggPSBDb2x1bW4sIHkgPSBSb3csIGZpbGwgPSB0cmVhdG1lbnQpKQoKbGF5b3V0X3Bsb3QgKyBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siKSArCiAgICBzY2FsZV95X3JldmVyc2UoYnJlYWtzID0gMToxNiwgbGFiZWxzID0gTEVUVEVSU1sxOjE2XSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MjQpICsKICAgIHNjYWxlX2ZpbGxfdGFibGVhdShuYW1lID0gInNpUk5BIikgKwogICAgZ2d0aXRsZSgic2lSTkEgTGF5b3V0IikKYGBgCgpgYGB7ciBuX2NlbGxzSGVhdG1hcCwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDgsIGVjaG89RkFMU0V9Cm5fY2VsbHNfaGVhdG1hcF9wbG90IDwtIGdncGxvdChkdF9kYXRhLCBhZXMoeCA9IENvbHVtbiwgeSA9IFJvdywgZmlsbCA9IGNlbGxfbnVtYmVyKSkKCm5fY2VsbHNfaGVhdG1hcF9wbG90ICsgZ2VvbV90aWxlKGNvbG9yID0gImJsYWNrIikgKwogICAgc2NhbGVfeV9yZXZlcnNlKGJyZWFrcyA9IDE6MTYsIGxhYmVscyA9IExFVFRFUlNbMToxNl0pICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjI0KSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXMoIkNlbGwgTnVtYmVyIikgKwogICAgZmFjZXRfd3JhcCh+IFBsYXRlTmFtZSwgbmNvbCA9IDEpICsKICAgIGdndGl0bGUoIkNlbGxzIE51bWJlciIpCmBgYAoKYGBge3IgYXJlYUhlYXRtYXAsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSA4LCBlY2hvPUZBTFNFfQphcmVhX2hlYXRtYXBfcGxvdCA8LSBnZ3Bsb3QoZHRfZGF0YSwgYWVzKHggPSBDb2x1bW4sIHkgPSBSb3csIGZpbGwgPSBudWNfYXJlYSkpCgphcmVhX2hlYXRtYXBfcGxvdCArIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsKICAgIHNjYWxlX3lfcmV2ZXJzZShicmVha3MgPSAxOjE2LCBsYWJlbHMgPSBMRVRURVJTWzE6MTZdKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToyNCkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzKCJBcmVhIFvCtW3Csl0iKSArCiAgICBmYWNldF93cmFwKH4gUGxhdGVOYW1lLCBuY29sID0gMSkgKwogICAgZ2d0aXRsZSgiUmF3IEFyZWEgTWVhc3VyZW1lbnQiKQpgYGAKCmBgYHtyIHJvdW5kSGVhdG1hcCwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDgsLCBlY2hvPUZBTFNFfQpyb3VuZF9oZWF0bWFwX3Bsb3QgPC0gZ2dwbG90KGR0X2RhdGEsIGFlcyh4ID0gQ29sdW1uLCB5ID0gUm93LCBmaWxsID0gbnVjX3JvdW5kbmVzcykpCgpyb3VuZF9oZWF0bWFwX3Bsb3QgKyBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siKSArCiAgICBzY2FsZV95X3JldmVyc2UoYnJlYWtzID0gMToxNiwgbGFiZWxzID0gTEVUVEVSU1sxOjE2XSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MjQpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpcygiUm91bmRuZXNzIikgKwogICAgZmFjZXRfd3JhcCh+IFBsYXRlTmFtZSwgbmNvbCA9IDEpICsKICAgIGdndGl0bGUoIlJhdyBSb3VuZG5lc3MgTWVhc3VyZW1lbnQiKQpgYGAKCmBgYHtyIG51Y1JlZEhlYXRtYXAsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSA4LCBlY2hvPUZBTFNFfQpudWNfcmVkX2hlYXRtYXBfcGxvdCA8LSBnZ3Bsb3QoZHRfZGF0YSwgYWVzKHggPSBDb2x1bW4sIHkgPSBSb3csIGZpbGwgPSBudWNfcmVkX2ludCkpCgpudWNfcmVkX2hlYXRtYXBfcGxvdCArIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsKICAgIHNjYWxlX3lfcmV2ZXJzZShicmVha3MgPSAxOjE2LCBsYWJlbHMgPSBMRVRURVJTWzE6MTZdKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToyNCkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzKHBhc3RlKHJlZF9uYW1lLCJOdWNsZWFyIEludGVuc2l0eSAoQS5VLikiKSkgKwogICAgZmFjZXRfd3JhcCh+IFBsYXRlTmFtZSwgbmNvbCA9IDEpICsKICAgIGdndGl0bGUocGFzdGUocmVkX25hbWUsICJOdWNsZWFyIEludGVuc2l0eSIpKQpgYGAKCmBgYHtyIG51Y2dyZWVuSGVhdG1hcCwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDgsIGVjaG89RkFMU0V9Cm51Y19ncmVlbl9oZWF0bWFwX3Bsb3QgPC0gZ2dwbG90KGR0X2RhdGEsIGFlcyh4ID0gQ29sdW1uLCB5ID0gUm93LCBmaWxsID0gbnVjX2dyZWVuX2ludCkpCgpudWNfZ3JlZW5faGVhdG1hcF9wbG90ICsgZ2VvbV90aWxlKGNvbG9yID0gImJsYWNrIikgKwogICAgc2NhbGVfeV9yZXZlcnNlKGJyZWFrcyA9IDE6MTYsIGxhYmVscyA9IExFVFRFUlNbMToxNl0pICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjI0KSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXMocGFzdGUoZ3JlZW5fbmFtZSwiTnVjbGVhciBJbnRlbnNpdHkgKEEuVS4pIikpICsKICAgIGZhY2V0X3dyYXAofiBQbGF0ZU5hbWUsIG5jb2wgPSAxKSArCiAgICBnZ3RpdGxlKHBhc3RlKGdyZWVuX25hbWUsICJOdWNsZWFyIEludGVuc2l0eSIpKQpgYGAKClF1aXRlIGEgZmV3IHdlbGxzIGluIEhUSUYwMDE4MyBjbGVhcmx5IGhhZCBhbiBpc3N1ZSwgZWl0aGVyIGR1ZSB0byB0aGUgc2FtcGxlIGl0c2VsZiwgb3IgdG8gdGhlIGF1dG9mb2N1cy4gRm9yIHRoaXMgcmVhc29uLCAqKnRoZXNlIHdlbGxzIHdpbGwgYmUgZWxpbWluYXRlZCBmcm9tIHRoZSBhbmFseXNpcyoqLgoKYGBge3J9CgpleGNsdWRlZCA8LSBjKCJNNyIsICJONyIsICJPNyIsICJQNyIsICJPOCIsICJQOCIpCgpkdF9kYXRhIDwtIGR0X2RhdGFbIShQbGF0ZU5hbWUgPT0gIkhUSUYwMDE4MyIgJiBXZWxsTmFtZSAlaW4lIGV4Y2x1ZGVkKSxdCmBgYAoKQ2FsY3VsYXRlIHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpdGF0aW9uIChTRCkgZm9yIHRoZSBuZWdhdGl2ZSBjb250cm9sIHNpUk5BIG9uIGEgcGVyIHBsYXRlIGJhc2lzLgoKYGBge3J9CmR0X25vcm0gPC0KICAgIGR0X2RhdGFbdHJlYXRtZW50ID09ICJuZWdhdGl2ZSIsIC4oCiAgICBuZWdfbl9jZWxsc19tZWFuID0gbWVhbihjZWxsX251bWJlciwgbmEucm0gPSBUUlVFKSwKICAgIG5lZ19uX2NlbGxzX3NkID0gc2QoY2VsbF9udW1iZXIsIG5hLnJtID0gVFJVRSksCiAgICBuZWdfYXJlYV9tZWFuID0gbWVhbihudWNfYXJlYSwgbmEucm0gPSBUUlVFKSwKICAgIG5lZ19hcmVhX3NkID0gc2QobnVjX2FyZWEsIG5hLnJtID0gVFJVRSksCiAgICBuZWdfcm91bmRfbWVhbiA9IG1lYW4obnVjX3JvdW5kbmVzcywgbmEucm0gPSBUUlVFKSwKICAgIG5lZ19yb3VuZF9zZCA9IHNkKG51Y19yb3VuZG5lc3MsIG5hLnJtID0gVFJVRSksCiAgICBuZWdfbnVjX3JlZF9tZWFuID0gbWVhbihudWNfcmVkX2ludCwgbmEucm0gPSBUUlVFKSwKICAgIG5lZ19udWNfcmVkX3NkID0gc2QobnVjX3JlZF9pbnQsIG5hLnJtID0gVFJVRSksCiAgICBuZWdfbnVjX2dyZWVuX21lYW4gPSBtZWFuKG51Y19ncmVlbl9pbnQsIG5hLnJtID0gVFJVRSksCiAgICBuZWdfbnVjX2dyZWVuX3NkID0gc2QobnVjX2dyZWVuX2ludCwgbmEucm0gPSBUUlVFKQogICAgKSwgYnkgPSAuaWRdCgpnbGltcHNlKGR0X25vcm0pCmBgYAoKQ2FsY3VsYXRlIFotc2NvcmVzIGJhc2VkIG9uIHRoZSBtZWFuIGFuZCBTRCBvZiB0aGUgbmVnYXRpdmUgY29udHJvbHMuIEFsc28gY2FsY3VsYXRlIHRoZSBuZWdhdGl2ZSBjb250cm9sIG5vcm1hbGl6ZWQgdmFsdWVzIChPbiBhIHBlciBwbGF0ZSBiYXNpcykuCgpgYGB7cn0KZHRfZGF0YSA8LSBkdF9kYXRhW2R0X25vcm0sIG9uID0gIi5pZCJdCgp6X3Njb3JlIDwtIGZ1bmN0aW9uKG1lYXN1cmVtZW50LCBhdmVyYWdlLCBzX2Rldil7CiAgICAgICAgICAgcmV0dXJuKChtZWFzdXJlbWVudCAtIGF2ZXJhZ2UpL3NfZGV2KQp9Cgpub3JtX2NoYW5nZSA8LWZ1bmN0aW9uKG1lYXN1cmVtZW50LCBhdmVyYWdlKXsKICAgICAgICAgICAgcmV0dXJuKDEwMCoobWVhc3VyZW1lbnQvYXZlcmFnZSkpCn0KCmR0X2RhdGFbLCBgOj1gKG5fY2VsbHNfel9zY29yZSA9IHpfc2NvcmUoY2VsbF9udW1iZXIsIG5lZ19uX2NlbGxzX21lYW4sIG5lZ19uX2NlbGxzX3NkKSwKICAgICAgICAgICAgICAgbl9jZWxsc19ub3JtX2NoYW5nZSA9IG5vcm1fY2hhbmdlKGNlbGxfbnVtYmVyLCBuZWdfbl9jZWxsc19tZWFuKSwKICAgICAgICAgICAgICAgYXJlYV96X3Njb3JlID0gel9zY29yZShudWNfYXJlYSwgbmVnX2FyZWFfbWVhbiwgbmVnX2FyZWFfc2QpLAogICAgICAgICAgICAgICBhcmVhX25vcm1fY2hhbmdlID0gbm9ybV9jaGFuZ2UobnVjX2FyZWEsIG5lZ19hcmVhX21lYW4pLAogICAgICAgICAgICAgICByb3VuZF96X3Njb3JlID0gel9zY29yZShudWNfcm91bmRuZXNzLCBuZWdfcm91bmRfbWVhbiwgbmVnX3JvdW5kX3NkKSwKICAgICAgICAgICAgICAgcm91bmRfbm9ybV9jaGFuZ2UgPSBub3JtX2NoYW5nZShudWNfcm91bmRuZXNzLCBuZWdfcm91bmRfbWVhbiksCiAgICAgICAgICAgICAgIG51Y19yZWRfel9zY29yZSA9IHpfc2NvcmUobnVjX3JlZF9pbnQsIG5lZ19udWNfcmVkX21lYW4sIG5lZ19udWNfcmVkX3NkKSwKICAgICAgICAgICAgICAgbnVjX3JlZF9ub3JtX2NoYW5nZSA9IG5vcm1fY2hhbmdlKG51Y19yZWRfaW50LCBuZWdfbnVjX3JlZF9tZWFuKSwKICAgICAgICAgICAgICAgbnVjX2dyZWVuX3pfc2NvcmUgPSB6X3Njb3JlKG51Y19ncmVlbl9pbnQsIG5lZ19udWNfZ3JlZW5fbWVhbiwgbmVnX251Y19ncmVlbl9zZCksCiAgICAgICAgICAgICAgIG51Y19ncmVlbl9ub3JtX2NoYW5nZSA9IG5vcm1fY2hhbmdlKG51Y19ncmVlbl9pbnQsIG5lZ19udWNfZ3JlZW5fbWVhbikpXQoKZ2xpbXBzZShkdF9kYXRhKQpgYGAKCldyaXRlIHRoZSBkYXRhIHRvIGEgLmNzdiBmaWxlIGZvciBmdXJ0aGVyIGFuYWx5c2lzCgpgYGB7cn0Kd3JpdGUudGFibGUoZHRfZGF0YSwgCiAgICAgICAgICAgIHBhc3RlKCJvdXRwdXQvdmFsaWRhdGlvbiIsIHJlZF9uYW1lLCBncmVlbl9uYW1lLCAibm9ybWFsaXplZF9yZXN1bHRzLnR4dCIsIHNlcCA9ICJfIiksCiAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsCiAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLCAKICAgICAgICAgICAgY29sLm5hbWVzID0gVFJVRSkKYGBgCgpDcmVhdGUgYSBub3ZlbCB1bmlxdWUgaWRlbnRpZmllciBmb3IgZWFjaCBvbGlnbyB0aGF0IGNvbnRhaW5zIGFsc28gdGhlIGdlbmUgc3ltYm9sLgoKYGBge3J9CmR0X2RhdGFbLG9saWdvX25hbWUgOj0gcGFzdGUoZ2VuZV9zeW1ib2wsIHN0cl9leHRyYWN0KG9saWdvX2lkLCAiWzAtOV17Mn0kIiksIHNlcCA9ICItIildCmBgYAoKYGBge3Igbl9jZWxsc1pQbG90LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0yNSwgZWNobz1GQUxTRX0KdGhlbWVfdXBkYXRlKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplID0gNikpCgpuX2NlbGxzX3Bsb3RfejwtIGdncGxvdChkdF9kYXRhWyEoaXMubmEob2xpZ29faWQpKSxdLCBhZXMoeCA9IG9saWdvX25hbWUsIHkgPSBuX2NlbGxzX3pfc2NvcmUpKQoKbl9jZWxsc19wbG90X3ogKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpKSArIAogICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgICAgICAgICAgIAogICAgICAgICAgICB4bGFiKCJzaVJOQSBpZCIpICsKICAgICAgICAgICAgeWxhYigiWi1zY29yZSArLy0gU0QiKSArCiAgICAgICAgICAgIGdndGl0bGUoIkNlbGwgTnVtYmVyIikKYGBgCgpgYGB7ciBuX2NlbGxzTm9ybVBsb3QsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTI1LCBlY2hvPUZBTFNFfQpuX2NlbGxzX3Bsb3RfZm9sZCA8LSBnZ3Bsb3QoZHRfZGF0YVshKGlzLm5hKG9saWdvX2lkKSksXSwgYWVzKHggPSBvbGlnb19uYW1lLCB5ID0gbl9jZWxsc19ub3JtX2NoYW5nZSkpCgpuX2NlbGxzX3Bsb3RfZm9sZCArIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX3NkbCIsIGZ1bi5hcmdzID0gbGlzdChtdWx0ID0gMSkpICsgCiAgICAgICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwMCkgKwogICAgICAgICAgICAKICAgICAgICAgICAgeGxhYigic2lSTkEgaWQiKSArCiAgICAgICAgICAgIHlsYWIoIiUgTmVnYXRpdmUgQ29udHJvbCArLy0gU0QiKSArCiAgICAgICAgICAgIGdndGl0bGUoIkNlbGwgTnVtYmVyIikKYGBgCgpgYGB7ciBhcmVhWlBsb3QsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTI1LCBlY2hvPUZBTFNFfQphcmVhX3Bsb3RfejwtIGdncGxvdChkdF9kYXRhWyEoaXMubmEob2xpZ29faWQpKSxdLCBhZXMoeCA9IG9saWdvX25hbWUsIHkgPSBhcmVhX3pfc2NvcmUpKQoKYXJlYV9wbG90X3ogKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpKSArIAogICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgICAgICAgICAgIAogICAgICAgICAgICB4bGFiKCJzaVJOQSBpZCIpICsKICAgICAgICAgICAgeWxhYigiWi1zY29yZSArLy0gU0QiKSArCiAgICAgICAgICAgIGdndGl0bGUoIk51Y2xlYXIgQXJlYSIpCmBgYAoKYGBge3IgYXJlYU5vcm1QbG90LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0yNSwgZWNobz1GQUxTRX0KYXJlYV9wbG90X2ZvbGQgPC0gZ2dwbG90KGR0X2RhdGFbIShpcy5uYShvbGlnb19pZCkpLF0sIGFlcyh4ID0gb2xpZ29fbmFtZSwgeSA9IGFyZWFfbm9ybV9jaGFuZ2UpKQoKYXJlYV9wbG90X2ZvbGQgKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpKSArIAogICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMDApICsKICAgICAgICAgICAgCiAgICAgICAgICAgIHhsYWIoInNpUk5BIGlkIikgKwogICAgICAgICAgICB5bGFiKCIlIE5lZ2F0aXZlIENvbnRyb2wgKy8tIFNEIikgKwogICAgICAgICAgICBnZ3RpdGxlKCJOdWNsZWFyIEFyZWEiKQpgYGAKCmBgYHtyIHJvdW5kWlBsb3QsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTI1LCBlY2hvPUZBTFNFfQpyb3VuZF9wbG90X3o8LSBnZ3Bsb3QoZHRfZGF0YVshKGlzLm5hKG9saWdvX2lkKSksXSwgYWVzKHggPSBvbGlnb19uYW1lLCB5ID0gcm91bmRfel9zY29yZSkpCgpyb3VuZF9wbG90X3ogKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpKSArIAogICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgICAgICAgICAgIAogICAgICAgICAgICB4bGFiKCJzaVJOQSBpZCIpICsKICAgICAgICAgICAgeWxhYigiWi1zY29yZSArLy0gU0QiKSArCiAgICAgICAgICAgIGdndGl0bGUoIk51Y2xlYXIgUm91bmRuZXNzIikKYGBgCgpgYGB7ciByb3VuZE5vcm1QbG90LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0yNSwgZWNobz1GQUxTRX0Kcm91bmRfcGxvdF9mb2xkIDwtIGdncGxvdChkdF9kYXRhWyEoaXMubmEob2xpZ29faWQpKSxdLCBhZXMoeCA9IG9saWdvX25hbWUsIHkgPSByb3VuZF9ub3JtX2NoYW5nZSkpCgpyb3VuZF9wbG90X2ZvbGQgKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpKSArIAogICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMDApICsKICAgICAgICAgICAgCiAgICAgICAgICAgIHhsYWIoInNpUk5BIGlkIikgKwogICAgICAgICAgICB5bGFiKCIlIE5lZ2F0aXZlIENvbnRyb2wgKy8tIFNEIikgKwogICAgICAgICAgICBnZ3RpdGxlKCJOdWNsZWFyIFJvdW5kbmVzcyIpCmBgYAoKYGBge3IgbnVjUmVkWlBsb3QsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTI1LCBlY2hvPUZBTFNFfQpudWNfcmVkX3Bsb3RfejwtIGdncGxvdChkdF9kYXRhWyEoaXMubmEob2xpZ29faWQpKSxdLCBhZXMoeCA9IG9saWdvX25hbWUsIHkgPSBudWNfcmVkX3pfc2NvcmUpKQoKbnVjX3JlZF9wbG90X3ogKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpKSArIAogICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgICAgICAgICAgIAogICAgICAgICAgICB4bGFiKCJzaVJOQSBpZCIpICsKICAgICAgICAgICAgeWxhYigiWi1zY29yZSArLy0gU0QiKSArCiAgICAgICAgICAgIGdndGl0bGUocGFzdGUocmVkX25hbWUsICJOdWNsZWFyIEludGVuc2l0eSIpKQpgYGAKCmBgYHtyIG51Y1JlZE5vcm1QbG90LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0yNSwgZWNobz1GQUxTRX0KbnVjX3JlZF9wbG90X2ZvbGQgPC0gZ2dwbG90KGR0X2RhdGFbIShpcy5uYShvbGlnb19pZCkpLF0sIGFlcyh4ID0gb2xpZ29fbmFtZSwgeSA9IG51Y19yZWRfbm9ybV9jaGFuZ2UpKQoKbnVjX3JlZF9wbG90X2ZvbGQgKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpKSArIAogICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMDApICsKICAgICAgICAgICAgCiAgICAgICAgICAgIHhsYWIoInNpUk5BIGlkIikgKwogICAgICAgICAgICB5bGFiKCIlIE5lZ2F0aXZlIENvbnRyb2wgKy8tIFNEIikgKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlKHJlZF9uYW1lLCAiTnVjbGVhciBJbnRlbnNpdHkiKSkKYGBgCgpgYGB7ciBudWNncmVlblpQbG90LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0yNSwgZWNobz1GQUxTRX0KbnVjX2dyZWVuX3Bsb3RfejwtIGdncGxvdChkdF9kYXRhWyEoaXMubmEob2xpZ29faWQpKSxdLCBhZXMoeCA9IG9saWdvX25hbWUsIHkgPSBudWNfZ3JlZW5fel9zY29yZSkpCgpudWNfZ3JlZW5fcGxvdF96ICsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gIm1lYW5fc2RsIiwgZnVuLmFyZ3MgPSBsaXN0KG11bHQgPSAxKSkgKyAKICAgICAgICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogICAgICAgICAgICAKICAgICAgICAgICAgeGxhYigic2lSTkEgaWQiKSArCiAgICAgICAgICAgIHlsYWIoIlotc2NvcmUgKy8tIFNEIikgKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlKGdyZWVuX25hbWUsICJOdWNsZWFyIEludGVuc2l0eSIpKQpgYGAKCmBgYHtyIG51Y2dyZWVuTm9ybVBsb3QsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTI1LCBlY2hvPUZBTFNFfQpudWNfZ3JlZW5fcGxvdF9mb2xkIDwtIGdncGxvdChkdF9kYXRhWyEoaXMubmEob2xpZ29faWQpKSxdLCBhZXMoeCA9IG9saWdvX25hbWUsIHkgPSBudWNfZ3JlZW5fbm9ybV9jaGFuZ2UpKQoKbnVjX2dyZWVuX3Bsb3RfZm9sZCArIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX3NkbCIsIGZ1bi5hcmdzID0gbGlzdChtdWx0ID0gMSkpICsgCiAgICAgICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwMCkgKwogICAgICAgICAgICAKICAgICAgICAgICAgeGxhYigic2lSTkEgaWQiKSArCiAgICAgICAgICAgIHlsYWIoIiUgTmVnYXRpdmUgQ29udHJvbCArLy0gU0QiKSArCiAgICAgICAgICAgIGdndGl0bGUocGFzdGUoZ3JlZW5fbmFtZSwgIk51Y2xlYXIgSW50ZW5zaXR5IikpCmBgYAoKQWdncmVnYXRlIHRoZSBiaW9sb2dpY2FsIHJlcGVhdHMgKFRoZSB0d28gZGlmZmVyZW50IHBsYXRlcykgYnkgY2FsY3VsYXRpbmcgdGhlIG1lYW4gYW5kIFNEIGZvciBhbGwgdGhlIHZhcmlhYmxlcyAoWi1zY29yZXMgYW5kIGZvbGQgY2hhbmdlcykuICoqbiA9IDIqKi4KCmBgYHtyfQpkdF9hZ2dyZWdhdGVkIDwtIGR0X2RhdGEgJT4lIAogICAgICAgIGdyb3VwX2J5KGdlbmVfc3ltYm9sLAogICAgICAgICAgICAgICAgIGdlbmVfaWQsCiAgICAgICAgICAgICAgICAgb2xpZ29faWQsCiAgICAgICAgICAgICAgICAgb2xpZ29fbmFtZSwKICAgICAgICAgICAgICAgICBzZXF1ZW5jZSkgJT4lCiAgICAgICAgc3VtbWFyaXNlKGFjcm9zcyhuX2NlbGxzX3pfc2NvcmU6bnVjX2dyZWVuX25vcm1fY2hhbmdlLCBsaXN0KG1lYW4sIHNkKSkpICU+JQogICAgICAgIGFycmFuZ2Uob2xpZ29fbmFtZSkKCndyaXRlLnRhYmxlKGR0X2FnZ3JlZ2F0ZWQsIAogICAgICAgICAgICBwYXN0ZSgib3V0cHV0L3ZhbGlkYXRpb24iLCByZWRfbmFtZSwgZ3JlZW5fbmFtZSwgImFnZ3JlZ2F0ZWRfcmVzdWx0cy50eHQiLCBzZXAgPSAiXyIpLAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLAogICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSwgCiAgICAgICAgICAgIGNvbC5uYW1lcyA9IFRSVUUpCmBgYAoKRG9jdW1lbnQgdGhlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBhbmFseXNpcyBzZXNzaW9uCgpgYGB7ciBzZXNzaW9uSW5mbywgaW5jbHVkZT1UUlVFLCBlY2hvPVRSVUUsIHJlc3VsdHM9J21hcmt1cCd9CnNlc3Npb25JbmZvKCkKYGBgCg==